home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * *
- * TCPStream.C *
- * *
- * Provides a simplified High Level interface to TCP. *
- * *
- * All routines have a state flag which will be > 0 while the call is *
- * in progress and <= 0 when completed. The low-level routines are *
- * called asynchronously and the high level routine returns. *
- * *
- * *
- * Written by Casper Boon, April, 1992. *
- * *
- * © 1992, CorkScrew Computer Technologies. *
- * *
- ************************************************************************/
-
- #include <MacTCPCommonTypes.h>
- #include <CvtAddr.h>
- #include <TCPPB.h>
-
- #include "BackGrounder.H"
- #include "TCPStream.H"
-
- extern Boolean debugOn;
-
- #define kBufferLen 16384
- #define kMaxConnections 20
- #define kTimeOut 40
-
- void TCPSError(StringPtr s, integer e);
-
- /************************************************************************/
- typedef struct
- {
- TCPiopb rpb; /* a Param Block for reading */
- TCPiopb wpb; /* a Param Block for writing */
- integer *rstate; /* a result code for reading */
- integer *wstate; /* a result code for writing */
- integer *rsize; /* a size for reading */
- integer *reof; /* read at eof (connection closed) */
- ip_addr remoteHost;
- tcp_port remotePort;
- ip_addr localHost;
- tcp_port localPort;
- Boolean opened;
- Boolean termValid;
- integer refNum;
- StreamPtr streamPtr; /* the stream associated with this */
- Word termReason;
- struct ICMPReport icmpMsg;
- } TCP_;
-
-
- /* opening call back routines */
- static void MadeConnection(integer flag, Ptr param);
- /* reading call back routines */
- static void ReadDone(integer flag, Ptr param);
- /* writing call back routines */
- static void WriteDone(integer flag, Ptr param);
- /* closing call back routines */
- static void CloseDone(integer flag, Ptr param);
- static void ReleaseDone(integer flag, Ptr param);
-
- void WaitForState(integer *state);
-
- pascal char *ReturnA5(void) = { 0x2E8D };
-
-
- static TCP_ * tcpBlkBuf[kMaxConnections] = {
- NIL, NIL, NIL, NIL, NIL,
- NIL, NIL, NIL, NIL, NIL,
- NIL, NIL, NIL, NIL, NIL,
- NIL, NIL, NIL, NIL, NIL
- };
- static integer _tcpRefNum = 0;
-
-
- /************************************************************************
- * *
- * Initialise local data buffers and open the TCP Driver *
- * *
- ************************************************************************/
- OSErr InitTCPS()
- {
- integer i;
- for (i = 0; i < kMaxConnections; i++)
- tcpBlkBuf[i] = NIL;
- return OpenDriver("\p.IPP", &_tcpRefNum);
- }
-
-
- /************************************************************************
- * *
- * Close any connections and dispose of the data buffers *
- * The TCP driver should not be closed because other applications may *
- * be using it. It would return a closeErr error anyway. *
- * *
- ************************************************************************/
- void ExitTCPS()
- {
- integer i;
- for (i = 0; i < kMaxConnections; i++)
- {
- if (tcpBlkBuf[i] != NIL)
- {
- TCP_ *tcpBlock = tcpBlkBuf[i];
- TCPiopb *pBlock = &tcpBlock->wpb;
- OSErr err;
-
- /*** abort the connection ***/
- ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
- pBlock->csCode = TCPAbort;
- pBlock->ioCRefNum = _tcpRefNum;
- pBlock->ioCompletion = NIL;
- pBlock->tcpStream = tcpBlock->streamPtr;
- err = PBControl((ParmBlkPtr)pBlock, FALSE);
-
- /*** release the stream ***/
- ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
- pBlock->csCode = TCPRelease;
- pBlock->ioCRefNum = _tcpRefNum;
- pBlock->tcpStream = tcpBlock->streamPtr;
- pBlock->csParam.create.userDataPtr = NIL;
- err = PBControl((ParmBlkPtr)pBlock, FALSE);
-
- /*** dispose of our memory ***/
- DisposPtr(pBlock->csParam.create.rcvBuff);
- DisposPtr((Ptr)tcpBlock);
- }
- }
- }
-
-
- /************************************************************************
- * *
- * Open a TCP connection. If a remote host name is provided the name *
- * will first be resolved by a call to the DNR. The boolean flag *
- * "passive" detirmines if the connection should be opened now or if we *
- * just listen for attempts to connect on the port. *
- * *
- ************************************************************************/
- OSErr TCPSOpen( integer *crefnum,
- char *remoteHost,
- Word localPort,
- Word remotePort,
- Boolean passive,
- integer *ostate)
- {
- OSErr err;
- TCPiopb *pBlock;
- TCP_ *tcpBlock;
- LongWord netNum = 0;
- integer index;
- Ptr connectionBuffer;
-
- /*** if we have a name, resolve it ***/
- if (remoteHost)
- {
- if ( (err = ConvertStringToAddr(remoteHost, &netNum)) != noErr )
- {
- TCPSError("\pTCPSOpen cannot resolve name", err);
- *ostate = err;
- return err;
- }
- }
-
- /*** allocate a stream record ***/
- tcpBlock = (TCP_ *)NewPtrClear(sizeof(TCP_));
- if ( (err = MemError()) != noErr)
- {
- TCPSError("\pTCPSOpen cannot allocate parm block", err);
- *ostate = err;
- return err;
- }
-
- /*** Allocate stream buffer ***/
- connectionBuffer = NewPtr(kBufferLen);
- if ( (err = MemError()) != noErr)
- {
- TCPSError("\pTCPSOpen cannot allocate rcv buf", err);
- DisposPtr((Ptr)tcpBlock);
- *ostate = err;
- return err;
- }
-
- /*** find a free stream pointer ***/
- for (index = 0; index < kMaxConnections; index++)
- if ( !tcpBlkBuf[index] )
- {
- tcpBlkBuf[index] = tcpBlock;
- *crefnum = (tcpBlock->refNum = (index + 1));
- break;
- }
-
- /*** initialise the stream record ***/
- tcpBlock->remoteHost = netNum;
- tcpBlock->localPort = localPort;
- tcpBlock->remotePort = remotePort;
- tcpBlock->rstate = ostate;
- tcpBlock->opened = FALSE;
- *ostate = 1;
-
- pBlock = &tcpBlock->rpb;
-
- /*** create the stream ***/
- pBlock->csCode = TCPCreate;
- pBlock->ioResult = 1;
- pBlock->ioCRefNum = _tcpRefNum;
- pBlock->ioCompletion = NIL;
- pBlock->ioNamePtr = ReturnA5();
-
- pBlock->csParam.create.rcvBuff = connectionBuffer;
- pBlock->csParam.create.rcvBuffLen = kBufferLen;
- pBlock->csParam.create.notifyProc = NIL;
- pBlock->csParam.create.userDataPtr = NIL;
-
- if ( (err = PBControl((ParmBlkPtr)pBlock, FALSE)) != noErr )
- {
- TCPSError("\pTCPSOpen create stream error", err);
- return err;
- }
-
- /*** save the stream pointer ***/
- tcpBlock->streamPtr = pBlock->tcpStream;
-
- ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
- pBlock->ioResult = 1;
- pBlock->ioCRefNum = _tcpRefNum;
- pBlock->ioCompletion = NIL;
- pBlock->ioNamePtr = ReturnA5();
- pBlock->tcpStream = tcpBlock->streamPtr;
- if (passive)
- {
- pBlock->csCode = TCPPassiveOpen;
- pBlock->csParam.open.ulpTimeoutValue = 0; /* use default */
- pBlock->csParam.open.commandTimeoutValue = 0; /* wait forever */
- }
- else
- {
- pBlock->csCode = TCPActiveOpen;
- pBlock->csParam.open.ulpTimeoutValue = kTimeOut;
- pBlock->csParam.open.commandTimeoutValue = kTimeOut;
- }
- pBlock->csParam.open.ulpTimeoutAction = 1;
- pBlock->csParam.open.validityFlags = 0xC0;
- pBlock->csParam.open.remoteHost = tcpBlock->remoteHost;
- pBlock->csParam.open.remotePort = tcpBlock->remotePort;
- pBlock->csParam.open.localPort = tcpBlock->localPort;
- pBlock->csParam.open.tosFlags = 0;
- pBlock->csParam.open.precedence = 0;
- pBlock->csParam.open.dontFrag = 0;
- pBlock->csParam.open.timeToLive = 0;
- pBlock->csParam.open.security = 0;
- pBlock->csParam.open.optionCnt = 0;
- pBlock->csParam.open.userDataPtr = NIL;
-
- /*** Open the connection asynchronously and wait in the background for a result ***/
- if ( (err = PBControl((ParmBlkPtr)pBlock, TRUE)) == noErr )
- Background(&pBlock->ioResult, MadeConnection, (Ptr)tcpBlock);
- else
- MadeConnection(err, (Ptr)tcpBlock);
-
- TCPSError("\pTCPSOpen result", err);
-
- return err;
- }
-
-
-
- /************************************************************************
- * *
- * When the open connection call completes the backgrounder calls this *
- * routine to save results, and to clean up if it failed *
- * *
- ************************************************************************/
- static void MadeConnection(integer flag, Ptr param)
- {
- TCP_ *tcpBlock = (TCP_*)param;
- TCPiopb *pBlock = &tcpBlock->rpb;
- OSErr err;
-
- tcpBlock->remoteHost = pBlock->csParam.open.remoteHost;
- tcpBlock->remotePort = pBlock->csParam.open.remotePort;
- tcpBlock->localHost = pBlock->csParam.open.localHost;
- tcpBlock->localPort = pBlock->csParam.open.localPort;
-
- if (!flag)
- tcpBlock->opened = TRUE;
- else
- { /*** bummer, close it up ***/
- TCPSClose(tcpBlock->refNum, &err);
- WaitForState(&err);
- }
-
- *(tcpBlock->rstate) = flag;
- }
-
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- OSErr TCPSRead(integer crefnum, Ptr data, integer *size,
- integer *eof, integer *rstate)
- {
- TCP_ *tcpBlock;
- TCPiopb *pBlock;
- OSErr err;
-
- if ( crefnum <= 0 || crefnum > kMaxConnections || !tcpBlkBuf[crefnum-1] )
- {
- *rstate = rfNumErr;
- return rfNumErr;
- }
-
- tcpBlock = tcpBlkBuf[crefnum-1];
-
- if ( !tcpBlock->opened )
- {
- *eof = TRUE;
- *rstate = notOpenErr;
- return notOpenErr;
- }
-
- if (*size <= 0) /* nothing to do */
- {
- *rstate = noErr;
- return noErr;
- }
-
- pBlock = &tcpBlock->rpb;
-
- tcpBlock->rsize = size;
- tcpBlock->rstate = rstate;
- tcpBlock->reof = eof;
- *rstate = 1;
- *eof = FALSE;
-
- ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
- pBlock->csCode = TCPRcv;
- pBlock->ioResult = 1;
- pBlock->ioCRefNum = _tcpRefNum;
- pBlock->ioCompletion = NIL;
- pBlock->ioNamePtr = ReturnA5();
- pBlock->tcpStream = tcpBlock->streamPtr;
- pBlock->csParam.receive.commandTimeoutValue = kTimeOut;
- pBlock->csParam.receive.rcvBuff = data;
- pBlock->csParam.receive.rcvBuffLen = *size;
- pBlock->csParam.receive.userDataPtr = NIL;
-
- if ( ! (err = PBControl((ParmBlkPtr)pBlock, TRUE)) )
- Background(&pBlock->ioResult, ReadDone, (Ptr)tcpBlock);
- else
- {
- pBlock->csParam.receive.rcvBuffLen = 0;
- ReadDone(err, (Ptr)tcpBlock);
- }
-
- TCPSError("\pTCPSRead result", err);
-
- return err;
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- static
- void ReadDone(integer flag, Ptr param)
- {
- TCP_ *tcpBlock = (TCP_*)param;
- TCPiopb *pBlock = &tcpBlock->rpb;
-
- TCPSError("\pTCPSRead Done result", flag);
-
- if (flag == connectionClosing) *(tcpBlock->rsize) = 0;
- else *(tcpBlock->rsize) = pBlock->csParam.receive.rcvBuffLen;
- *(tcpBlock->rstate) = flag;
- *(tcpBlock->reof) = (flag == connectionClosing ||
- flag == connectionTerminated);
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- OSErr TCPSWrite(integer crefnum, Ptr data, integer size, integer *wstate)
- {
- TCP_ *tcpBlock;
- TCPiopb *pBlock;
- struct wdsEntry *theWDS;
- OSErr err;
-
- if ( crefnum <= 0 || crefnum > kMaxConnections || !tcpBlkBuf[crefnum-1] )
- {
- *wstate = rfNumErr;
- return rfNumErr;
- }
-
- tcpBlock = tcpBlkBuf[crefnum-1];
-
- if ( !tcpBlock->opened )
- {
- *wstate = notOpenErr;
- return notOpenErr;
- }
-
- if (size <= 0) /* nothing to do */
- {
- *wstate = noErr;
- return noErr;
- }
-
- pBlock = &tcpBlock->wpb;
-
- tcpBlock->wstate = wstate;
- *wstate = 1;
-
- theWDS = (wdsEntry *)NewPtr( (2*sizeof(wdsEntry)) );
- if ( (err = MemError()) != noErr)
- {
- TCPSError("\pTCPSWrite cannot allocate WDS", err);
- *wstate = err;
- return err;
- }
-
- theWDS[0].length = size;
- theWDS[0].ptr = data;
- theWDS[1].length = 0;
- theWDS[1].ptr = 0;
-
- ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
- pBlock->csCode = TCPSend;
- pBlock->ioResult = 1;
- pBlock->ioCRefNum = _tcpRefNum;
- pBlock->ioCompletion = NIL;
- pBlock->ioNamePtr = ReturnA5();
- pBlock->tcpStream = tcpBlock->streamPtr;
- pBlock->csParam.send.ulpTimeoutValue = kTimeOut;
- pBlock->csParam.send.ulpTimeoutAction = 1;
- pBlock->csParam.send.validityFlags = 0xC0;
- pBlock->csParam.send.pushFlag = FALSE;
- pBlock->csParam.send.urgentFlag = FALSE;
- pBlock->csParam.send.wdsPtr = (Ptr)theWDS;
- pBlock->csParam.send.userDataPtr = NIL;
-
- if ( ! (err = PBControl((ParmBlkPtr)pBlock, TRUE)) )
- Background(&pBlock->ioResult, WriteDone, (Ptr)tcpBlock);
- else
- WriteDone(err, (Ptr)tcpBlock);
-
- TCPSError("\pTCPSWrite result", err);
-
- return err;
- }
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- static void WriteDone(integer flag, Ptr param)
- {
- TCP_ *tcpBlock = (TCP_*)param;
- TCPiopb *pBlock = &tcpBlock->wpb;
-
- TCPSError("\pTCPSWrite Done result", flag);
-
- *(tcpBlock->wstate) = flag;
- DisposPtr((Ptr)pBlock->csParam.send.wdsPtr);
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- OSErr TCPSClose(integer crefnum, integer *cstate)
- {
- TCP_ *tcpBlock;
- TCPiopb *pBlock;
- OSErr err = -23008; /* connection Doesnt Exist */
-
- if ( crefnum <= 0 || crefnum > kMaxConnections || !tcpBlkBuf[crefnum-1] )
- {
- *cstate = rfNumErr;
- return rfNumErr;
- }
-
-
- tcpBlock = tcpBlkBuf[crefnum-1];
- tcpBlkBuf[crefnum-1] = NIL; /* free this entry */
-
- *cstate = 1;
-
- /* first kill any pending IO requests */
- if (tcpBlock->opened)
- {
- tcpBlock->opened = FALSE; /* we are closing */
-
- if (tcpBlock->wpb.ioResult > 0)
- PBKillIO((ParmBlkPtr)&tcpBlock->wpb, FALSE);
- if (tcpBlock->wpb.ioResult > 0) tcpBlock->wpb.ioResult=-1;
- RunBackground();
- if (tcpBlock->rpb.ioResult > 0)
- PBKillIO((ParmBlkPtr)&tcpBlock->rpb, FALSE);
- if (tcpBlock->rpb.ioResult > 0) tcpBlock->rpb.ioResult=-1;
- RunBackground();
- }
-
- tcpBlock->wstate = cstate;
-
- pBlock = &tcpBlock->wpb;
-
- ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
- pBlock->csCode = TCPClose;
- pBlock->ioResult = 1;
- pBlock->ioCRefNum = _tcpRefNum;
- pBlock->ioCompletion = NIL;
- pBlock->ioNamePtr = ReturnA5();
- pBlock->tcpStream = tcpBlock->streamPtr;
- pBlock->csParam.close.ulpTimeoutValue = kTimeOut;
- pBlock->csParam.close.ulpTimeoutAction = 1;
- pBlock->csParam.close.validityFlags = 0xC0;
- pBlock->csParam.close.userDataPtr = NIL;
-
- if ( ! (err = PBControl((ParmBlkPtr)pBlock, TRUE)) )
- Background(&pBlock->ioResult, CloseDone, (Ptr)tcpBlock);
- else
- CloseDone(err, (Ptr)tcpBlock);
-
- TCPSError("\pTCPSClose result", err);
-
- return err;
- }
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- static void CloseDone(integer flag, Ptr param)
- {
- TCP_ *tcpBlock = (TCP_*)param;
- TCPiopb *pBlock = &tcpBlock->wpb;
- OSErr err;
-
- if (flag)
- {
- ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
- pBlock->csCode = TCPAbort;
- pBlock->ioCRefNum = _tcpRefNum;
- pBlock->ioCompletion = NIL;
- pBlock->tcpStream = tcpBlock->streamPtr;
- err = PBControl((ParmBlkPtr)pBlock, FALSE);
- }
-
- ClearBytes((Ptr)pBlock, sizeof(TCPiopb));
- pBlock->csCode = TCPRelease;
- pBlock->ioCRefNum = _tcpRefNum;
- pBlock->tcpStream = tcpBlock->streamPtr;
- pBlock->csParam.create.userDataPtr = NIL;
- err = PBControl((ParmBlkPtr)pBlock, FALSE);
-
- TCPSError("\pTCPSClose Done result", err);
-
- *(tcpBlock->wstate) = err;
- DisposPtr(pBlock->csParam.create.rcvBuff);
- DisposPtr((Ptr)tcpBlock);
- }
-
-
-
- /************************************************************************
- * *
- * *
- ************************************************************************/
- OSErr TCPSConnInfo(integer crefnum,
- LongWord *localHost, LongWord *remoteHost,
- Word *localPort, Word *remotePort)
- {
- TCP_ *tcpBlock;
-
- if ( crefnum <= 0 || crefnum > kMaxConnections || !tcpBlkBuf[crefnum-1] )
- return badUnitErr;
-
- tcpBlock = tcpBlkBuf[crefnum-1];
-
- *localHost = tcpBlock->localHost;
- *remoteHost = tcpBlock->remoteHost;
- *localPort = tcpBlock->localPort;
- *remotePort = tcpBlock->remotePort;
-
- return 0;
- }
-
- /************************************************************************
- * *
- * This was for the future (which never came) *
- * *
- ************************************************************************/
- pascal void StreamNotifyProc (
- StreamPtr tcpStream,
- Word eventCode,
- Ptr userDataPtr,
- Word terminReason,
- struct ICMPReport *icmpMsg);
-
- pascal void StreamNotifyProc (
- StreamPtr tcpStream,
- Word eventCode,
- Ptr userDataPtr,
- Word terminReason,
- struct ICMPReport *icmpMsg)
- {
- }
-
-
- /************************************************************************
- * *
- * Display an error message when something goes wrong. *
- * We only do this if we are debugging, otherwise the error should be *
- * picked up and display by whatever called the TCPStream routine that *
- * caused the error. *
- * *
- ************************************************************************/
- void TCPSError(StringPtr s, integer e)
- {
- Str255 str;
- extern integer stdlog;
-
- if (e == noErr) return; /* nothing to report */
-
- if (!debugOn) return; /* actually not interested at this stage */
-
- if (stdlog)
- {
- log_printf("%p %d\n", s, e);
- return;
- }
-
- psprintf(str, "TCP Stream Error\015\015%p\015 errNo %d", s, e);
- ParamText(str, NIL, NIL, NIL); /* tell dialog manager */
-
- InternalAlert();
- }
-